﻿using System;
using System.Collections.Generic;
using Jay.Sc2.Bof.Lib.Action;
using Jay.Sc2.Bof.Lib.Action.Zerg;

namespace Jay.Sc2.Bof.Lib.State
{
	public class ZergState : State
	{
		public ZergState() : base(ZergRace.Instance) { }
		public class ZergBuilding : StateBuilding
		{
			public ZergBuilding Clone()
			{
				ZergBuilding clone = new ZergBuilding();
				clone.Building = Building;
				clone.Count = Count;
				return clone;
			}
		}
		public class ZergProudctionBuilding : ZergBuilding
		{
			public virtual int AvailableForProduction { get { return Count - Production; } }
			public int AvailableForUpgrade { get { return Count - Upgrade; } }
			public override int Available { get { return Math.Min(AvailableForProduction, AvailableForUpgrade); } }
			public void Produced() { Production--; }
			public void Upgraded() { Upgrade--; }
			public int Production;
			public int Upgrade;
			public new ZergProudctionBuilding Clone()
			{
				ZergProudctionBuilding clone = new ZergProudctionBuilding();
				clone.Building = Building;
				clone.Count = Count;
				clone.Production = Production;
				clone.Upgrade = Upgrade;
				return clone;
			}
		}
		public class ZergUpgrade : StateUpgrade
		{
			public ZergUpgrade Clone()
			{
				ZergUpgrade clone = new ZergUpgrade();
				clone.Available = Available;
				clone.Researching = Researching;
				return clone;
			}
		}

		public static ZergState CreateInitialState()
		{
			ZergState state = new ZergState();
			state.TotalBases.Count = state.Hatchery.Count = 1;
			state.Minerals = 50;
			state.WorkersOnMinerals = state.Food = state.Drone = 6;
			state.Overlord = 1;
			state.Supply = state.Hatchery.Count * 2 + (state.Overlord + state.Overseer) * 8;
			state.Larva = 3;
			// maybe zerg player start with less than 3 larva, i must check that in game too ;)
			return state;
		}

		public ZergProudctionBuilding Hatchery = new ZergProudctionBuilding();
		public ZergBuilding Extractor = new ZergBuilding();
		public ZergProudctionBuilding SpawningPool = new ZergProudctionBuilding();
		public ZergProudctionBuilding EvolutionChamber = new ZergProudctionBuilding();
		public ZergProudctionBuilding SpineCrawler = new ZergProudctionBuilding();
		public ZergProudctionBuilding SporeCrawler = new ZergProudctionBuilding();
		public ZergProudctionBuilding HydraliskDen = new ZergProudctionBuilding();
		public ZergProudctionBuilding BanelingNest = new ZergProudctionBuilding();
		public ZergProudctionBuilding Lair = new ZergProudctionBuilding();
		public ZergProudctionBuilding RoachWarren = new ZergProudctionBuilding();
		public ZergProudctionBuilding InfestationPit = new ZergProudctionBuilding();
		public ZergProudctionBuilding Spire = new ZergProudctionBuilding();
		public ZergProudctionBuilding NydusNetwork = new ZergProudctionBuilding();
		public ZergProudctionBuilding Hive = new ZergProudctionBuilding();
		public ZergProudctionBuilding UltraliskCavern = new ZergProudctionBuilding();
		public ZergProudctionBuilding GreaterSpire = new ZergProudctionBuilding();
		public ZergProudctionBuilding CreepTumor = new ZergProudctionBuilding();
		public int Larva;
		public int Drone;
		public int Overlord;
		public int Zergling;
		public int Queen;
		public int Hydralisk;
		public int Baneling;
		public int Overseer;
		public int Roach;
		public int Infestor;
		public int InfestedTerran;
		public int Mutalisk;
		public int Corruptor;
		public int NydusWorm;
		public int Ultralisk;
		public int BroodLord;
		public int Broodling;
		public int Changeling;
		public int Infiltrator;
		public int Drone_Building;
		public int Zergling_Building;
		public int Overlord_Building;
		public int Corruptor_Building;
		public int Queen_Building;

		public List<double> Queen_Energy = new List<double>();
		public override void IncrementTime()
		{
			base.IncrementTime();
			for (int c = 0; c < Queen_Energy.Count; c++)
				if (Queen_Energy[c] < 200)
					Queen_Energy[c] = Math.Min(Queen_Energy[c] + 0.56, 200);
		}
		private int m_BaseProducingLarva = 0;
		public void UseLarva(IBuildOrder bo)
		{
			Larva--;
			ProduceLarva(bo);
		}
		public void ProduceLarva(IBuildOrder bo)
		{
			if (m_BaseProducingLarva < Bases.Count)
			{
				m_BaseProducingLarva++;
				bo.AddAction(Time + 15, new ActionGeneric("ActionSpawnLarva", SpawnLarva));
			}
		}
		private static void SpawnLarva(IBuildOrder ibo)
		{
			ZergState istate = ibo.State as ZergState;
			// maybe we should check here too if we can spawn the larva, i dont know zerg race that much, i have to try in game ;)
			istate.Larva++;
			if (istate.Larva < 3 * istate.Bases.Count)
				ibo.AddAction(istate.Time + 15, new ActionGeneric("ActionSpawnLarva", SpawnLarva));
			else
				istate.m_BaseProducingLarva--;
		}

		public ZergBuilding TotalBases = new ZergBuilding();
		public override IBuilding Bases { get { return TotalBases; } }

		public override IBuilding GasBuilding { get { return Extractor; } }

		public override int Army
		{
			get
			{
				return (Zergling + Baneling) / 2 +
					Queen * 2 +
					Hydralisk * 2 +
					Roach * 2 +
					Infestor * 2 +
					Mutalisk * 2 +
					Corruptor * 2 +
					Ultralisk * 6 +
					BroodLord * 4;
			}
		}

		public override int Workers { get { return Drone; } set { Drone = value; } }

		public override double Score(IState state)
		{
			ZergState s = state as ZergState;
			double score = 0;
			score += Score(Drone, s.Drone, 50.0);
			score += Score(Baneling, s.Baneling, 75.0);
			score += Score(BanelingNest, s.BanelingNest, 150);
			score += Score(BroodLord, s.BroodLord, 300);
			score += Score(Corruptor, s.Corruptor, 250);
			score += Score(EvolutionChamber, s.EvolutionChamber, 75);
			score += Score(Extractor, s.Extractor, 25);
			score += Score(GreaterSpire, s.GreaterSpire, 250);
			score += Score(Hatchery, s.Hatchery, 300);
			score += Score(Hive, s.Hive, 350);
			score += Score(Hydralisk, s.Hydralisk, 150);
			score += Score(HydraliskDen, s.HydraliskDen, 200);
			score += Score(InfestationPit, s.InfestationPit, 200);
			score += Score(Infestor, s.Infestor, 250);
			score += Score(Lair, s.Lair, 250);
			score += Score(Mutalisk, s.Mutalisk, 150.0);
			score += Score(NydusNetwork, s.NydusNetwork, 350);
			score += Score(NydusWorm, s.NydusWorm, 200);
			score += Score(Overlord, s.Overlord, 100);
			score += Score(Overseer, s.Overseer, 150);
			score += Score(Queen, s.Queen, 150);
			score += Score(Roach, s.Roach, 100);
			score += Score(RoachWarren, s.RoachWarren, 150);
			score += Score(SpawningPool, s.SpawningPool, 200);
			score += Score(SpineCrawler, s.SpineCrawler, 100);
			score += Score(Spire, s.Spire, 400);
			score += Score(SporeCrawler, s.SporeCrawler, 75);
			score += Score(Ultralisk, s.Ultralisk, 500);
			score += Score(UltraliskCavern, s.UltraliskCavern, 350);
			score += Score(Zergling, s.Zergling, 25);
			///TODO add the upgrades
			score += Score((int)this.Minerals, (int)s.Minerals, 1.0);
			score += Score((int)this.Gas, (int)s.Gas, 1.0);
			return score;
		}

		public override bool IsSatisfying(IState goal)
		{
			ZergState s = goal as ZergState;
			if (Drone < s.Drone) return false;
			if (Baneling < s.Baneling) return false;
			if (BanelingNest.Count < s.BanelingNest.Count) return false;
			if (BroodLord < s.BroodLord) return false;
			if (Corruptor < s.Corruptor) return false;
			if (EvolutionChamber.Count < s.EvolutionChamber.Count) return false;
			if (Extractor.Count < s.Extractor.Count) return false;
			if (GreaterSpire.Count < s.GreaterSpire.Count) return false;
			if (Hatchery.Count < s.Hatchery.Count) return false;
			if (Hive.Count < s.Hive.Count) return false;
			if (Hydralisk < s.Hydralisk) return false;
			if (HydraliskDen.Count < s.HydraliskDen.Count) return false;
			if (InfestationPit.Count < s.InfestationPit.Count) return false;
			if (Infestor < s.Infestor) return false;
			if (Lair.Count < s.Lair.Count) return false;
			if (Mutalisk < s.Mutalisk) return false;
			if (NydusNetwork.Count < s.NydusNetwork.Count) return false;
			if (NydusWorm < s.NydusWorm) return false;
			if (Overlord < s.Overlord) return false;
			if (Overseer < s.Overseer) return false;
			if (Queen < s.Queen) return false;
			if (Roach < s.Roach) return false;
			if (RoachWarren.Count < s.RoachWarren.Count) return false;
			if (SpawningPool.Count < s.SpawningPool.Count) return false;
			if (SpineCrawler.Count < s.SpineCrawler.Count) return false;
			if (Spire.Count < s.Spire.Count) return false;
			if (SporeCrawler.Count < s.SporeCrawler.Count) return false;
			if (Ultralisk < s.Ultralisk) return false;
			if (UltraliskCavern.Count < s.UltraliskCavern.Count) return false;
			if (Zergling < s.Zergling) return false;
			///TODO add the upgrades
			if (Minerals < s.Minerals) return false;
			if (Gas < s.Gas) return false;
			return true;
		}

		public override IState Clone()
		{
			ZergState clone = new ZergState();
			clone.Queen_Energy = new List<double>(Queen_Energy);
			clone.Drone_Building = Drone_Building;
			clone.Zergling_Building = Zergling_Building;
			clone.Overlord_Building = Overlord_Building;
			clone.Corruptor_Building = Corruptor_Building;
			clone.Queen_Building = Queen_Building;
			clone.Drone = Drone;
			clone.Baneling = Baneling;
			clone.BanelingNest = BanelingNest.Clone();
			clone.BroodLord = BroodLord;
			clone.Corruptor = Corruptor;
			clone.EvolutionChamber = EvolutionChamber.Clone();
			clone.Extractor = Extractor.Clone();
			clone.GreaterSpire = GreaterSpire.Clone();
			clone.Hatchery = Hatchery.Clone();
			clone.Hive = Hive.Clone();
			clone.Hydralisk = Hydralisk;
			clone.HydraliskDen = HydraliskDen.Clone();
			clone.InfestationPit = InfestationPit.Clone();
			clone.Infestor = Infestor;
			clone.Lair = Lair.Clone();
			clone.Mutalisk = Mutalisk;
			clone.NydusNetwork = NydusNetwork.Clone();
			clone.NydusWorm = NydusWorm;
			clone.Overlord = Overlord;
			clone.Overseer = Overseer;
			clone.Queen = Queen;
			clone.Roach = Roach;
			clone.RoachWarren = RoachWarren.Clone();
			clone.SpawningPool = SpawningPool.Clone();
			clone.SpineCrawler = SpineCrawler.Clone();
			clone.Spire = Spire.Clone();
			clone.SporeCrawler = SporeCrawler.Clone();
			clone.Ultralisk = Ultralisk;
			clone.UltraliskCavern = UltraliskCavern.Clone();
			clone.Zergling = Zergling;
			///TODO add the upgrades
			clone.TotalBases = TotalBases.Clone();
			clone.Larva = Larva;
			clone.m_BaseProducingLarva = m_BaseProducingLarva;
			clone.m_SupplyBuilding = m_SupplyBuilding;
			clone.Food = Food;
			clone.Supply = Supply;
			clone.WorkersOnMinerals = WorkersOnMinerals;
			clone.WorkersOnGas = WorkersOnGas;
			clone.Time = Time;
			clone.Minerals = Minerals;
			clone.Gas = Gas;
			return clone;
		}

		public override IList<IAction> NeededActions
		{
			get
			{
				List<IAction> al = new List<IAction>();
				AddNeededAction(al, Drone - 6, ActionProduceDrone.Instance);
				AddNeededAction(al, Baneling, ActionProduceBaneling.Instance);
				AddNeededAction(al, BanelingNest, ActionProduceBanelingNest.Instance);
				AddNeededAction(al, Hatchery.Count + Lair.Count + Hive.Count, ActionProduceHatchery.Instance);
				AddNeededAction(al, BroodLord, ActionProduceBroodLord.Instance);
				AddNeededAction(al, Corruptor + BroodLord, ActionProduceCorruptor.Instance);
				AddNeededAction(al, EvolutionChamber, ActionProduceEvolutionChamber.Instance);
				AddNeededAction(al, Extractor, ActionProduceExtractor.Instance);
				AddNeededAction(al, Hydralisk, ActionProduceHydralisk.Instance);
				AddNeededAction(al, HydraliskDen, ActionProduceHydraliskDen.Instance);
				AddNeededAction(al, InfestationPit, ActionProduceInfestationPit.Instance);
				AddNeededAction(al, Infestor, ActionProduceInfestor.Instance);
				AddNeededAction(al, Lair.Count + Hive.Count, ActionProduceLair.Instance);
				AddNeededAction(al, Mutalisk, ActionProduceMutalisk.Instance);
				AddNeededAction(al, NydusNetwork, ActionProduceNydusNetwork.Instance);
				AddNeededAction(al, Overlord + Overseer, ActionProduceOverlord.Instance);
				AddNeededAction(al, Overseer, ActionProduceOverseer.Instance);
				AddNeededAction(al, Queen, ActionProduceQueen.Instance);
				AddNeededAction(al, Roach, ActionProduceRoach.Instance);
				AddNeededAction(al, RoachWarren, ActionProduceRoachWarren.Instance);
				AddNeededAction(al, SpawningPool, ActionProduceSpawningPool.Instance);
				AddNeededAction(al, SpineCrawler, ActionProduceSpineCrawler.Instance);
				AddNeededAction(al, Spire.Count + GreaterSpire.Count, ActionProduceSpire.Instance);
				AddNeededAction(al, GreaterSpire, ActionProduceGreaterSpire.Instance);
				AddNeededAction(al, SporeCrawler, ActionProduceSporeCrawler.Instance);
				AddNeededAction(al, Ultralisk, ActionProduceUltralisk.Instance);
				AddNeededAction(al, UltraliskCavern, ActionProduceUltraliskCavern.Instance);
				AddNeededAction(al, (Zergling + Baneling) / 2, ActionProduceZergling.Instance);
				return al;
			}
		}

		public override IActionList BasicBuildOrder
		{
			get
			{
				ActionList al = new ActionList(ZergRace.Instance);
				AddNeededActionWithRequirements(al, Drone - 6, ActionProduceDrone.Instance);
				AddNeededActionWithRequirements(al, Baneling, ActionProduceBaneling.Instance);
				AddNeededActionWithRequirements(al, BanelingNest, ActionProduceBanelingNest.Instance);
				AddNeededActionWithRequirements(al, Hatchery.Count + Lair.Count + Hive.Count, ActionProduceHatchery.Instance);
				AddNeededActionWithRequirements(al, BroodLord, ActionProduceBroodLord.Instance);
				AddNeededActionWithRequirements(al, Corruptor + BroodLord, ActionProduceCorruptor.Instance);
				AddNeededActionWithRequirements(al, EvolutionChamber, ActionProduceEvolutionChamber.Instance);
				AddNeededActionWithRequirements(al, Extractor, ActionProduceExtractor.Instance);
				AddNeededActionWithRequirements(al, Hydralisk, ActionProduceHydralisk.Instance);
				AddNeededActionWithRequirements(al, HydraliskDen, ActionProduceHydraliskDen.Instance);
				AddNeededActionWithRequirements(al, InfestationPit, ActionProduceInfestationPit.Instance);
				AddNeededActionWithRequirements(al, Infestor, ActionProduceInfestor.Instance);
				AddNeededActionWithRequirements(al, Lair.Count + Hive.Count, ActionProduceLair.Instance);
				AddNeededActionWithRequirements(al, Mutalisk, ActionProduceMutalisk.Instance);
				AddNeededActionWithRequirements(al, NydusNetwork, ActionProduceNydusNetwork.Instance);
				//AddBasicAction(al, NydusWorm, ActionProduceObserver.Instance);
				AddNeededActionWithRequirements(al, Overlord + Overseer, ActionProduceOverlord.Instance);
				AddNeededActionWithRequirements(al, Overseer, ActionProduceOverseer.Instance);
				AddNeededActionWithRequirements(al, Queen, ActionProduceQueen.Instance);
				AddNeededActionWithRequirements(al, Roach, ActionProduceRoach.Instance);
				AddNeededActionWithRequirements(al, RoachWarren, ActionProduceRoachWarren.Instance);
				AddNeededActionWithRequirements(al, SpawningPool, ActionProduceSpawningPool.Instance);
				AddNeededActionWithRequirements(al, SpineCrawler, ActionProduceSpineCrawler.Instance);
				AddNeededActionWithRequirements(al, Spire.Count + GreaterSpire.Count, ActionProduceSpire.Instance);
				AddNeededActionWithRequirements(al, GreaterSpire, ActionProduceGreaterSpire.Instance);
				AddNeededActionWithRequirements(al, SporeCrawler, ActionProduceSporeCrawler.Instance);
				AddNeededActionWithRequirements(al, Ultralisk, ActionProduceUltralisk.Instance);
				AddNeededActionWithRequirements(al, UltraliskCavern, ActionProduceUltraliskCavern.Instance);
				AddNeededActionWithRequirements(al, Zergling / 2, ActionProduceZergling.Instance);
				return al;
			}
		}
	}
}
